import type { ComputedRef, Ref } from 'vue';
import type { FormProps, FormSchema, FormActionType } from '../types/form';
import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw, reactive, nextTick } from 'vue';
import { isArray, isFunction, isObject, isString, isDef, isNullOrUnDef, isEmpty } from '@/utils/is';
import { deepMerge } from '@/utils';
import { dateItemType, handleInputNumberValue, defaultValueComponents } from '../helper';

import { dateDayjs } from '@/utils/date';
import { cloneDeep, uniqBy } from 'lodash-es';
import { error } from '@/utils/log';

interface UseFormActionContext {
  emit: EmitType;
  getProps: ComputedRef<FormProps>;
  getSchema: ComputedRef<FormSchema[]>;
  formModel: Recordable;
  defaultValueRef: Ref<Recordable>;
  formElRef: Ref<FormActionType>;
  schemaRef: Ref<FormSchema[]>;
  handleFormValues: Fn;
}

interface AnyFormState { [key: string]: any }

export const formCopyModel = reactive<Recordable>({});

export function useFormEvents({
  emit,
  getProps,
  formModel,
  getSchema,
  defaultValueRef,
  formElRef,
  schemaRef,
  handleFormValues,
}: UseFormActionContext) {

  // 先对formModel进行拷贝
  Object.assign(formCopyModel, formModel);

  /**
   * @description: 重置表单方法
   */
  async function resetFields(): Promise<void> {

    const { resetFunc } = unref(getProps);
    resetFunc && isFunction(resetFunc) && (await resetFunc());

    const formEl = unref(formElRef);
    if (!formEl) return;

    Object.keys(formModel).forEach((key) => {
      const schema = unref(getSchema).find((item) => item.field === key);
      const isInput = schema?.component && defaultValueComponents.includes(schema.component);
      const defaultValue = cloneDeep(defaultValueRef.value[key]);
      formModel[key] = isInput ? (defaultValue || defaultValue == 0 ? defaultValue : undefined) : defaultValue;
    });

    // 清空拷贝的数据
    if(Object.keys(formCopyModel).length){ Object.keys(formCopyModel).forEach(key => delete formCopyModel[key]); }
    
    Object.assign(formCopyModel, formModel); // 重新赋值

    await nextTick(async() => await clearValidate());

    emit('reset', toRaw(formModel));
  }

  /**
   * @description: 按需重置表单方法
   */
  async function needsResetFields(name?:string[]): Promise<void> {
    
    const { resetFunc } = unref(getProps);
    resetFunc && isFunction(resetFunc) && (await resetFunc());

    const formEl = unref(formElRef);
    if (!formEl) return;

    if(!isArray(name)) return;
    
    name.forEach((key) => {
      const schema = unref(getSchema).find((item) => item.field === key);
      const isInput = schema?.component && defaultValueComponents.includes(schema.component);
      const defaultValue = cloneDeep(defaultValueRef.value[key]);
      formModel[key] = isInput ? (defaultValue || defaultValue == 0 ? defaultValue : undefined) : defaultValue;
      formCopyModel[key] = isInput ? (defaultValue || defaultValue == 0 ? defaultValue : undefined) : defaultValue;

      if(!formModel[key]) {
        if(formModel[key] != 0){
          delete formModel[key];
          delete formCopyModel[key]; 
        }
      }

    });
    // console.log('needsResetFields', formModel);

    await nextTick(async() => await clearValidate());

    emit('reset', toRaw(formModel));
  }

  /**
   * @description: Set form value
   */
  async function setFieldsValue(values: Recordable): Promise<void> {
    const fields = unref(getSchema)
      .map((item) => item.field)
      .filter(Boolean);

    // key 支持 a.b.c 的嵌套写法
    const delimiter = '.';
    const nestKeyArray = fields.filter((item) => item.indexOf(delimiter) >= 0);

    const validKeys: string[] = [];
    Object.keys(values).forEach((key) => {
      const schema = unref(getSchema).find((item) => item.field === key);
      let value = values[key];

      const hasKey = Reflect.has(values, key);

      value = handleInputNumberValue(schema?.component, value);
      // 0| '' is allow
      if (hasKey && fields.includes(key)) {
        // 处理 时间类型
        if (itemIsDateType(key)) {
          // 处理时间类型为数组的情况
          if (Array.isArray(value)) {
            const { componentProps } = schema || {};
            const _props = componentProps as any;
            const arr: any[] = [];
            for (const ele of value) {
              const date = ele ? _props?.valueFormat ? dateDayjs(ele).format(_props?.valueFormat) : isString(ele) ? ele : dateDayjs(ele) : null;
              arr.push(date);
            }
            formModel[key] = arr;
          } else {
            const { componentProps } = schema || {};
            let _props = componentProps as any;
            if (typeof componentProps === 'function') {
              _props = _props({ formModel });
            }
            formModel[key] = value ? (_props?.valueFormat ? value : dateDayjs(value)) : null;
            
            formCopyModel[key] = value ? (_props?.valueFormat ? value : dateDayjs(value)) : null;
          }
        } else {
          const { component, componentProps }:any = schema;
          // 处理为Select组件时，value值在options选项找不到对应数据的情况将value赋值为undefined;
          if(component == 'Select'){
            if(componentProps && Object.keys(componentProps).length && componentProps['options']){
              const options = componentProps['options'] || [];
              if(Array.isArray(value)){ // 判断值为数组的情况
                const valArr:any[] = [];
                value.forEach((itemValue: any) => {
                  const findList = options.filter((item:any) => item?.value === itemValue) || [];
                  if(findList.length > 0){
                    valArr.push(itemValue);
                  }
                });
                formModel[key] = valArr;
              }else{
                const findList = options.filter((item:any) => item?.value === value) || [];
                if(findList.length > 0){ 
                  formModel[key] = value;
                }else{
                  // 处理初始值不存在在options选项数据中;
                  if(unref(defaultValueRef)[key] || unref(defaultValueRef)[key] == 0){
                    formModel[key] = cloneDeep(unref(defaultValueRef)[key]);
                  }else{
                    formModel[key] = undefined;
                  }
                }
              }
            }else{
              formModel[key] = value;
            }
          }else{
            formModel[key] = value;
          }

          formCopyModel[key] = formModel[key];
        }

        // 再次判断一下是否需要进行校验的字段
        if (hasKey && fields.includes(key) && (formCopyModel[key] === undefined || formCopyModel[key] === null || formCopyModel[key] === '')){
          validKeys.push(key);
        }
      } else {
        nestKeyArray.forEach((nestKey: string) => {
          try {
            const value = nestKey.split('.').reduce((out, item) => out[item], values);
            if (isDef(value)) {
              formModel[nestKey] = value;
              formCopyModel[nestKey] = value;
              validKeys.push(nestKey);
            }
          } catch (e) {
            // key not exist
            if (isDef(defaultValueRef.value[nestKey])) {
              formModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
              formCopyModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
            }
          }
        });
      }
    });

    validateFields(validKeys).catch(() => {});
    
    // console.log('触发setFieldsValue:', formModel, '拷贝的数据:', formCopyModel);
  }

  /**
   * @description: 根据字段名称删除
   */
  async function removeSchemaByField(fields: string | string[]): Promise<void> {
    const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
    if (!fields) {
      return;
    }

    let fieldList: string[] = isString(fields) ? [fields] : fields;

    if (isString(fields)) { fieldList = [fields]; }

    for (const field of fieldList) {  _removeSchemaByField(field, schemaList); }

    schemaRef.value = schemaList;
  }

  /**
   * @description: Delete based on field name
   */
  function _removeSchemaByField(field: string, schemaList: FormSchema[]): void {
    if (isString(field)) {
      const index = schemaList.findIndex((schema) => schema.field === field);
      if (index !== -1) {
        delete formModel[field];
        schemaList.splice(index, 1);
      }
    }
  }

  /**
   * @description: Insert after a certain field, if not insert the last
   */
  async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
    const schemaList: FormSchema[] = cloneDeep(unref(getSchema));

    const index = schemaList.findIndex((schema) => schema.field === prefixField);

    if (!prefixField || index === -1 || first) {
      first ? schemaList.unshift(schema) : schemaList.push(schema);
      schemaRef.value = schemaList;
      _setDefaultValue(schema);
      return;
    }
    if (index !== -1) {
      schemaList.splice(index + 1, 0, schema);
    }
    _setDefaultValue(schema);

    schemaRef.value = schemaList;
  }

  async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
    let updateData: Partial<FormSchema>[] = [];
    if (isObject(data)) {
      updateData.push(data as FormSchema);
    }
    if (isArray(data)) {
      updateData = [...data];
    }

    const hasField = updateData.every(
      (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
    );

    if (!hasField) {
      error('需要更新的表单架构数组的所有子项都必须包含“field”字段!');
      return;
    }
    schemaRef.value = updateData as FormSchema[];
  }

  async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
    let updateData: Partial<FormSchema>[] = [];
    if (isObject(data)) {
      updateData.push(data as FormSchema);
    }
    if (isArray(data)) {
      updateData = [...data];
    }

    const hasField = updateData.every(
      (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field),
    );

    if (!hasField) {
      error('需要更新的表单架构数组的所有子项都必须包含“field”字段!');
      return;
    }
    const schema: FormSchema[] = [];
    unref(getSchema).forEach((val) => {
      if(updateData.length > 0){
        const item = updateData.find((item) => item?.field == val?.field);
        if(item && Object.keys(item).length > 0){
          const newSchema = deepMerge(val, item);
          schema.push(newSchema);
        }else{
          schema.push(val);
        }
      }else{
        schema.push(val);
      }
    });
    
    _setDefaultValue(schema);
    
    // 处理Select组件中options有数据的情况重新赋值
    if(schema && schema.length){
      const obj: Recordable = {};
      schema.forEach((item) => {
        const { component, componentProps }:any = item;
        if(component == 'Select'){
          if(componentProps && Object.keys(componentProps).length && componentProps['options']){
            const options = componentProps['options'] || [];
            
            const value = formCopyModel[item.field];
            if(Array.isArray(value)){ // 判断值为数组的情况
              const valArr:any[] = [];
              value.forEach((itemValue: any) => {
                const findList = options.filter((item:any) => item?.value === itemValue) || [];
                if(findList.length > 0){
                  valArr.push(itemValue);
                }
              });
              obj[item.field] = valArr;
            }else{
              const findList = options.filter((item:any) => item?.value === value) || [];
              if(findList.length > 0){ 
                obj[item.field] = value;
              }else{
                // 处理初始值不存在在options选项数据中;
                if(unref(defaultValueRef)[item.field] || unref(defaultValueRef)[item.field] == 0){
                  obj[item.field] = cloneDeep(unref(defaultValueRef)[item.field]);
                }else{
                  obj[item.field] = undefined;
                }
              }
            }
          }
        }
      });

      // console.log('触发updateSchema', formCopyModel, formModel);

      setFieldsValue(obj);
    }

    schemaRef.value = uniqBy(schema, 'field');

    await unref(formElRef)?.clearValidate(); // 清除因为更新数据导致的校验触发
  }

  function _setDefaultValue(data: FormSchema | FormSchema[]) {
    let schemas: FormSchema[] = [];
    if (isObject(data)) {
      schemas.push(data as FormSchema);
    }
    if (isArray(data)) {
      schemas = [...data];
    }

    const obj: Recordable = {};
    const currentFieldsValue = getFieldsValue();
    schemas.forEach((item) => {
      if ( item.component != 'Divider' && Reflect.has(item, 'field') && item.field &&
        !isNullOrUnDef(item.defaultValue) &&
        (!(item.field in currentFieldsValue) ||
          isNullOrUnDef(currentFieldsValue[item.field]) ||
          isEmpty(currentFieldsValue[item.field]))
      ) {
        const { componentProps, field }:any = item;
        if(item.component == 'Select'){
          if(componentProps && Object.keys(componentProps).length && componentProps['options']){
            const options = componentProps['options'] || [];
            const value = formCopyModel[field];
            if(Array.isArray(value)){ // 判断值为数组的情况
              const valArr:any[] = [];
              value.forEach((itemValue: any) => {
                const findList = options.filter((item:any) => item?.value === itemValue) || [];
                if(findList.length > 0){
                  valArr.push(itemValue);
                }
              });
              obj[field] = valArr;
            }else{
              const findList = options.filter((item:any) => item?.value === value) || [];
              if(findList.length > 0){ 
                obj[field] = value;
              }else{
                // 处理初始值不存在在options选项数据中;
                if(item.defaultValue || item.defaultValue == 0){
                  obj[field] = item.defaultValue; 
                }else{
                  obj[field] = undefined;
                }
              }
            }
          }
        }else{
          obj[field] = item.defaultValue; 
        }
      }
    });

    setFieldsValue(obj);
  }

  function getFieldsValue(): Recordable {
    const formEl = unref(formElRef);
    if (!formEl) return {};
    const form = handleReturnFormModel();
    return handleFormValues(form);
  }

  function handleReturnFormModel (form:object={}) {

    const formState:AnyFormState = Object.assign({}, form && Object.keys(form).length ? form : toRaw(formModel));

    Object.keys(formState).forEach((key) => {
      if(formState[key] === undefined){
        delete formState[key];
      }
    });
    // console.group('调用getFieldsValue触发：');
    // console.log('表单绑定值对象：', formState);
    return formState;
  }

  /**
   * @description: Is it time
   */
  function itemIsDateType(key: string) {
    return unref(getSchema).some((item:any) => {
      return item.field === key ? dateItemType.includes(item.component) : false;
    });
  }

  async function validateFields(nameList?: NamePath[] | undefined) {
    const formEl = unref(formElRef);
    if (!formEl) return {};
    const vform = await formEl?.validateFields(nameList);

    const formState = handleReturnFormModel(vform);

    const form = Object.assign({}, handleFormValues(formState));

    return form;
  }

  async function validate(nameList?: NamePath[] | undefined) {
    return await unref(formElRef)?.validate(nameList);
  }

  async function clearValidate(name?: string | string[]) {
    await unref(formElRef)?.clearValidate(name);
  }

  async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) {
    await unref(formElRef)?.scrollToField(name, options);
  }

  onBeforeUnmount(async() => {
    if(Object.keys(formCopyModel).length) Object.keys(formCopyModel).forEach(key => delete formCopyModel[key]);
    // console.log('卸载前：',formCopyModel);
  });

  return {
    clearValidate,
    validate,
    validateFields,
    getFieldsValue,
    updateSchema,
    resetSchema,
    appendSchemaByField,
    removeSchemaByField,
    resetFields,
    needsResetFields,
    setFieldsValue,
    scrollToField,
  };
}
